﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using RedFoxUtils;

namespace RedFoxSpamKiller
{
  public class SpamDatabase: IDisposable
  {
    class FileBackend : IBackend
    {
      private string spamDatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Dropbox", "RedFoxForumSpamKiller", "RedFoxSpamDatabase.txt");
      public FileBackend()
      {
      }

      public List<string> Load()
      {
        if (!File.Exists(spamDatabasePath))
        {
          Directory.CreateDirectory(new FileInfo(spamDatabasePath).Directory.FullName);
          File.WriteAllText(spamDatabasePath, "");
        }

        List<string> spamWords = new List<string>();
        string[] lines = File.ReadAllLines(spamDatabasePath, Encoding.UTF8);
        var wordsList = new List<string>();
        wordsList.AddRange(lines);

        spamWords.AddRange(wordsList.Where(word => !String.IsNullOrEmpty(word)));
        return spamWords;
      }

      public void save(List<string> spamWords)
      {
        File.WriteAllLines(spamDatabasePath, spamWords);
      }
    }

    class ServiceBackend : IBackend
    {
      public List<string> Load()
      {
        HttpClient client = new HttpClient();
        Stream data = client.OpenRead("http://redfoxspamdb.appspot.com/download");
        StreamReader reader = new StreamReader(data, Encoding.UTF8);
        string srcString = reader.ReadToEnd();
        data.Close();
        reader.Close();

        string[] lines = srcString.Split(Environment.NewLine.ToCharArray());
        var wordsList = new List<string>();
        wordsList.AddRange(lines);

        List<string> spamWords = new List<string>();
        spamWords.AddRange(wordsList.Where(word => !String.IsNullOrEmpty(word)));
        return spamWords;
      }
      public void save(List<string> spamWords)
      {
        string content = String.Join(Environment.NewLine, spamWords);
        HttpClient client = new HttpClient();

        string formatString = "text={0}&submit=Save";
        string postString = string.Format(formatString,
          content
          );

        //Change to byte[]
        byte[] postData = Encoding.UTF8.GetBytes(postString);

        client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        byte[] responseData = client.UploadData(new Uri("http://redfoxspamdb.appspot.com/upload"), "POST", postData);
        content = Encoding.UTF8.GetString(responseData);
        Debug.WriteLine(content);
      }
    }

    private IBackend backend=null;

    private List<string> spamWords = null;
    public List<string> SpamWords
    {
      get { return spamWords; }
      set { spamWords = value; }
    }

    private string spamDatabasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Dropbox", "RedFoxForumSpamKiller", "RedFoxSpamDatabase.txt");
    private SpamDatabase()
    {
      try
      {
        backend = new ServiceBackend();
      }
      catch (Exception ex)
      {
        //backend = new FileBackend();
        throw new Exception(String.Format("無法取得網路上的SPAM資料庫!原因：{0}", ex.Message));
      }
      spamWords = backend.Load();
    }

    /// <summary>
    /// Gets the instance.
    /// </summary>
    /// <returns></returns>
    public static SpamDatabase getInstance() {
      return new SpamDatabase();
    }

    public void Dispose()
    {
      save();
    }

    /// <summary>
    /// Saves.
    /// </summary>
    public void save()
    {
      backend.save(spamWords);
    }

    /// <summary>
    /// Matches the specified input.
    /// </summary>
    /// <param name="input">The input.</param>
    /// <returns></returns>
    public bool match(string input)
    {
      string title = removeReplyPrefix(input);
      foreach (var word in spamWords)
      {
        if (input.Contains(word))
          return true;
      }
      return false;
    }

    /// <summary>
    /// Removes the reply's prefix.  It return 123 if input is "回復：123".
    /// </summary>
    /// <param name="input">The input.</param>
    /// <returns></returns>
    private string removeReplyPrefix(string input)
    {
      if (input.StartsWith("回復："))
        return input.Substring(3);
      return input;
    }

    public void addWord( string input )
    {
      string title = removeReplyPrefix(input);
      if (!spamWords.Contains(title))
        spamWords.Add(title);
    }

    public void addWords(string[] inputs)
    {
      foreach (var word in inputs)
        if (!spamWords.Contains(word))
          addWord(word);
    }

    public void reload(string[] lines)
    {
      List<string> wordsList = new List<string>();
      wordsList.AddRange(lines);

      SpamWords.Clear();
      SpamWords.AddRange(wordsList.Where(word => !String.IsNullOrEmpty(word)));
      SpamWords.Sort();
    }
  }
}
